// Copyright 2019 The rhyme_lph Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// L [author] rhyme_lph
// R [email]  rhymelph@gmail.com
// T [github] https://github.com/rhymelph

import 'dart:async';

import 'package:base_plugin/base_plugin.dart';
import 'package:dio/src/response.dart';
import 'package:finance_app/generated/l10n.dart';
import 'package:finance_app/src/common/config.dart';
import 'package:finance_app/src/entities/custom_expense_data.dart';
import 'package:finance_app/src/entities/expense_detail_entity.dart';
import 'package:finance_app/src/http_service/http_expense_service.dart';
import 'package:finance_app/src/mixin/format_group_map_mixin.dart';
import 'package:finance_app/src/mixin/refresh_mixin.dart';
import 'package:finance_app/src/mixin/search_data_list_mixin.dart';
import 'package:finance_app/src/provider/dashboard_provider.dart';
import 'package:finance_app/src/provider/hr_payroll/hr_and_payroll_provider.dart';
import 'package:finance_app/src/provider/hr_payroll/views/reimburse_provider.dart';
import 'package:finance_app/src/router_gen/override_route_providers.dart';
import 'package:finance_app/src/router_gen/router_gen_providers.dart';
import 'package:finance_app/src/utils/permission_utils.dart';
import 'package:finance_app/src/widgets/bottom_sheet/delete_info_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/got_it_tip_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/judge_bottom_sheet.dart';
import 'package:flutter/material.dart';

class ReimburseApproveProvider extends BaseProvider<List<ExpenseDetailEntity>>
    with
        SearchDataListMixin,
        FormatGroupMapLocalMixin<ExpenseDetailEntity>,
        RefreshMixin<List<ExpenseDetailEntity>, List<ExpenseDetailEntity>> {
  List<ExpenseDetailEntity> currentSelectList = [];

  @override
  Future get dataFuture =>
      HttpExpenseService.reimbursementsList('pending', page);

  void onCancel() {
    currentSelectList.clear();
    update();
  }

  void onOperation(String operation) async {
    if (currentSelectList.length == 0) return;
    List<int> ids = currentSelectList.map((e) => e.id).toList();
    String name =
        currentSelectList.map((e) => e.paidBy).toSet().toList().join(', ');
    String numbers =
        currentSelectList.map((e) => e.number).toSet().toList().join(', ');
    switch (operation) {
      case 'Reimburse Now':
        double total = 0.0;
        currentSelectList.forEach((element) {
          total += element.total;
        });
        CustomExpenseData customData = CustomExpenseData(
            ids: ids,
            orderType: 'batch_reimburse_now',
            paidTo: name,
            number: numbers,
            totalAmount: total);

        final result =
            await Routes.navigateTo(RouterGenProviders.newCashOutPage, params: {
          'customExpenseData': customData,
        });

        if (result != null) {
          obtainContext?.call((context) async {
            await showExpenseClaimSuccessBottomSheet(context);
            update();
            updatePreviousPage();
            Navigator.of(context).pop();
          });
        }
        break;
      case 'Reimburse Later':
        currentSelectList.forEach((element) {
          ids.add(element.id);
        });
        obtainContext?.call((context) async {
          bool isSuccess =
              await showBulkReimburseLaterJudgeBottomSheet(context);
          if (isSuccess == true) {
            isSuccess = false;

            await post(
                HttpExpenseService.reimbursementsBatchReimburseLater(ids),
                autoHandler: AutoHandler.Toast,
                loadingTip: S.current.loading, onSuccess: (result) {
              isSuccess = true;
            });
            if (isSuccess) {
              await showGotItTipBottomSheet(context,
                  S.current.the_reimbursement_will_be_added_to_their_payslips);
              currentSelectList.clear();
              data.removeWhere((element) => ids.contains(element.id));
              data = transformData(data, false);
              update();
              updatePreviousPage();
              obtainContext?.call((context) {
                Navigator.of(context).pop();
              });
            }
          }
        });
        break;
      case 'Reject':
        obtainContext?.call((context) async {
          bool isSuccess = await showRejectExpenseClaimBottomSheet(context);
          if (isSuccess == true) {
            isSuccess = false;
            await post(HttpExpenseService.reimbursementsBatchReject(ids),
                autoHandler: AutoHandler.Toast,
                loadingTip: S.current.loading, onSuccess: (result) {
              isSuccess = true;
            });
            if (isSuccess) {
              await showExpenseRejectedSuccessBottomSheet(context);
              currentSelectList.clear();
              data.removeWhere((element) => ids.contains(element.id));
              data = transformData(data, false);
              updatePreviousPage();
              update();
              obtainContext?.call((context) {
                Navigator.of(context).pop();
              });
            }
          }
        });
        break;
      case 'Delete':
        obtainContext?.call((context) async {
          bool isSuccess = await showDeleteExpenseInfoBottomSheet(context);
          if (isSuccess == true) {
            isSuccess = false;
            await post(HttpExpenseService.batchExpenseDelete(ids),
                autoHandler: AutoHandler.Toast,
                loadingTip: S.current.loading, onSuccess: (result) {
              isSuccess = true;
            });
            if (isSuccess) {
              await showExpenseRejectedSuccessBottomSheet(context);
              currentSelectList.clear();
              data.removeWhere((element) => ids.contains(element.id));
              data = transformData(data, false);
              updatePreviousPage();
              update();
              obtainContext?.call((context) {
                Navigator.of(context).pop();
              });
            }
          }
        });
        break;
    }
  }

  void onDeselectAll() {
    currentSelectList.clear();
    update();
  }

  void onSelectAll() {
    currentSelectList.addAll(List.from(data));
    update();
  }

  void onSelect(ExpenseDetailEntity item1) {
    if (currentSelectList.contains(item1)) {
      currentSelectList.remove(item1);
    } else {
      currentSelectList.add(item1);
    }
    update();
  }

  @override
  FutureOr<List<ExpenseDetailEntity>> transformData(
      List<ExpenseDetailEntity> d, bool isCache) {
    hasUp = d.length >= rows;
    groupMap.clear();
    contactToMap(d);
    return super.transformData(d, isCache);
  }

  void contactToMap(List<ExpenseDetailEntity> list) {
    sortGroupToMap(
      list,
      sort: (a, b) => sortIssuesAt(b, a, (t) => t.issuedAt, (t) => t.id),
      group: (a) => groupMonth(a, (t) => t.issuedAt),
    );
  }

  @override
  void searchRefreshData(searchData) {
    contactToMap(data);
    update();
  }

  @override
  get dataList => data;

  @override
  getFromRequestResult(Response<dynamic> result, bool isRefresh) {
    if (isRefresh) {
      groupMap.clear();
    }
    List<ExpenseDetailEntity> paymentList =
        getEntityFromResult<List<ExpenseDetailEntity>>(result);
    contactToMap(paymentList);
    return paymentList;
  }

  void updatePreviousPage() {
    Providers.get<HrAndPayrollProvider>(
            RouterGenProviders.hrAndPayrollPage, null)
        ?.getChildProvider<ReimburseProvider>()
        ?.refreshController
        ?.requestRefresh();

    if (!Config.hasPermission(PermissionUtils.homeDashboard))
      Config.dashboardProvider
          ?.getChildProvider<HrAndPayrollProvider>()
          ?.getChildProvider<ReimburseProvider>()
          ?.refreshController
          ?.requestRefresh();
  }

  @override
  Future get refreshFuture => dataFuture;
}
